import numpy as np

RULES={
    "泵供水不足":{
        "fields": ["进口压力", "瞬时流量", "出口压力","泵平衡压力"],
        "label":{
            "errorUp":1,
            "errorDown":2,
            "warnUp":3,
            "warnDown":4,
        }
    },
    "泵润滑故障": {
        "fields": ["润滑油压力", "高架油箱液位", "地下油箱液位", "泵润滑油压力","泵前轴温度","泵后轴温度","前轴承温度","后轴承温度"],
        "label": {
            "errorUp": 5,
            "errorDown": 6,
            "warnUp": 7,
            "warnDown": 8,
        }
    },
    "电机运行故障":{
        "fields":["A相电压","B相电压","C相电压","A相电流","B相电流","C相电流","有功功率","无功功率","定子前部温度","定子中部温度","定子后部温度","前轴承温度","后轴承温度","电机冷却水压力","电机润滑油压力"],
        "label":{
            "errorUp": 9,
            "errorDown": 10,
            "warnUp": 11,
            "warnDown": 12,
        }
    }
}

def getTypeByLabel(label):
    idx=label//4
    return list(RULES.keys())[idx-1]

def getDescribeByLabel(label):
    type=getTypeByLabel(label)
    i=label%4
    warnOrError=0
    desc=""
    if i==0:
        desc="故障,"+type+",数值过高"
        warnOrError=1
    elif i==1:
        desc="故障,"+type+",数值过低"
        warnOrError=1
    elif i==2:
        desc="预警,"+type+",数值偏高"
        warnOrError=0
    elif i==3:
        desc="预警,"+type+",数值偏低"
        warnOrError=0
    return warnOrError,desc


def normalize(data,field2Idx,thresh):
    normData = np.zeros_like(data)
    for field in field2Idx:
        colData = data[:, field2Idx[field]]
        errorRan = thresh[field]["error"]
        colData = (colData - errorRan[0]) / (errorRan[1] - errorRan[0])
        colData[np.isnan(colData)] = np.nanmean(colData)  # 将nan值替换为均值
        if np.isnan(colData).any():  # 这一列全都为nan值的话nanmean值也为nan
            return None
        normData[:, field2Idx[field]] = colData
    return normData

def classify(data,field2Idx,thresh,warnNum=20,errorNum=1):
    """
    分类数据，给数据贴标签。
    :param data: numpy arrary, 二维数组多列数据
    :param field2Idx:dict, 字段和数据列索引的对应关系
    :param thresh:dict, 字段对应的阈值范围
    :param warnNum:int, 当数据中出现warnNum个超过预警范围的数据则认为需要预警
    :param errorNum:int, 当数据中出现errorNum个超过故障范围的数据则认为需要预警
    :return:(int,numpy array) 标签序号,按照error范围归一化的数据
    """
    type=None
    for field in field2Idx:
        colData=data[:,field2Idx[field]]
        errorRan=thresh[field]["error"]
        colData=(colData-errorRan[0])/(errorRan[1]-errorRan[0])
        colData[np.isnan(colData)]=np.nanmean(colData)#将nan值替换为均值
        if np.isnan(colData).any():#这一列全都为nan值的话nanmean值也为nan
            return None
        warnRan=thresh[field]["warn"]
        warnRan=[(warnRan[0]-errorRan[0])/(errorRan[1]-errorRan[0]),(warnRan[1]-errorRan[0])/(errorRan[1]-errorRan[0])]
        n=colData[colData<0].shape[0]
        if n>errorNum:
            type="errorDown"
            break
        n=colData[colData>1].shape[0]
        if n>errorNum:
            type="errorUp"
            break
        n=colData[colData<warnRan[0]].shape[0]
        if n > warnNum:
            type = "warnDown"
            break
        n=colData[colData>warnRan[1]].shape[0]
        if n > warnNum:
            type = "warnUp"
            break
    if type is None:
        return 0
    for key in RULES:
        if field in RULES[key]["fields"]:
            return RULES[key]["label"][type]
    return None